/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

size_t GetFunctionSize()
{
	return sizeof(struct ZlangFunction);
}

int InitFunctionParamter( struct ZlangRuntime *rt , struct ZlangFunctionParameter *param , char *parent_obj_name , char *obj_name )
{
	param->parent_obj_name = ZLSTRDUP( parent_obj_name ) ;
	if( param->parent_obj_name == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_STRDUP , "alloc memory for func param failed" )
		return ZLANG_ERROR_ALLOC;
	}
	
	if( obj_name )
	{
		param->obj_name = ZLSTRDUP( obj_name ) ;
		if( param->obj_name == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_STRDUP , "alloc memory for func param failed" )
			return ZLANG_ERROR_ALLOC;
		}
	}
	
	return 0;
}

struct ZlangFunctionParameter *AllocFunctionParamter( struct ZlangRuntime *rt , char *parent_obj_name , char *obj_name )
{
	struct ZlangFunctionParameter	*param = NULL ;
	
	int				nret = 0 ;
	
	param = (struct ZlangFunctionParameter *)ZLMALLOC( sizeof(struct ZlangFunctionParameter) ) ;
	if( param == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for func param failed" )
		return NULL;
	}
	memset( param , 0x00 , sizeof(struct ZlangFunctionParameter) );
	
	nret = InitFunctionParamter( rt , param , parent_obj_name , obj_name ) ;
	if( nret )
	{
		FreeFunctionParamter( param );
		return NULL;
	}
	
	return param;
}

int SetFunctionName( struct ZlangRuntime *rt , struct ZlangFunction *func , char *func_name )
{
	func->func_name = ZLSTRDUP( func_name ) ;
	if( func->func_name == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for func_name failed" )
		return -1;
	}
	
	return 0;
}

int SetFunctionName2( struct ZlangRuntime *rt , struct ZlangFunction *func , char *prefix , char *func_name )
{
	size_t		prefix_len = strlen(prefix) ;
	size_t		func_name_len = strlen(func_name) ;
	func->func_name = ZLMALLOC( prefix_len+func_name_len+1 ) ;
	if( func->func_name == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for func_name failed" )
		return -1;
	}
	memcpy( func->func_name , prefix , prefix_len );
	memcpy( func->func_name+prefix_len , func_name , func_name_len );
	func->func_name[prefix_len+func_name_len] = '\0' ;
	
	return 0;
}

char *GetFunctionName( struct ZlangFunction *func )
{
	if( func == NULL )
		return NULL;
	
	return func->func_name;
}

void LinkFullFunctionName( struct ZlangFunction *func , char *full_func_name )
{
	func->full_func_name = full_func_name ;
	
	return;
}

int SetFullFunctionName( struct ZlangRuntime *rt , struct ZlangFunction *func , char *full_func_name )
{
	func->full_func_name = ZLSTRDUP( full_func_name ) ;
	if( func->full_func_name == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for full_func_name failed" )
		return -1;
	}
	
	return 0;
}

char *GetFullFunctionName( struct ZlangFunction *func )
{
	if( func == NULL )
		return NULL;
	
	return func->full_func_name;
}

void SetFunctionAccessQuelifier( struct ZlangFunction *func , unsigned char access_qualifier )
{
	func->access_qualifier = access_qualifier ;
	return;
}

unsigned char GetFunctionAccessQuelifier( struct ZlangFunction *func )
{
	return func->access_qualifier;
}

void FreeFunctionParamter( struct ZlangFunctionParameter *func_param )
{
	if( func_param == NULL )
		return;
	
	if( func_param->parent_obj_name )
		ZLFREE( func_param->parent_obj_name );
	if( func_param->obj_name )
		ZLFREE( func_param->obj_name );
	
	ZLFREE( func_param );
	
	return;
}

char *GenerateFullFunctionName( struct ZlangRuntime *rt , struct ZlangFunction *func , struct list_head *in_params , struct ZlangFunctionParameter *out_param )
{
	char				full_function_name_buf[ 4096 ] = "" ;
	char				vargs_full_function_name_buf[ 4096 ] = "" ;
	char				*p = NULL ;
	size_t				remain_len ;
	size_t				len ;
	struct ZlangFunctionParameter	*first_func_param = NULL ;
	struct ZlangFunctionParameter	*func_param = NULL ;
	
	memset( full_function_name_buf , 0x00 , sizeof(full_function_name_buf) );
	memset( vargs_full_function_name_buf , 0x00 , sizeof(vargs_full_function_name_buf) );
	p = full_function_name_buf ;
	remain_len = sizeof(full_function_name_buf) - 1 ;
	
	len = snprintf( p , remain_len , "%s(" , func->func_name ) ;
	if( len >= 0 )
	{
		p += len ;
		remain_len -= len ;
	}
	
	if( ! list_empty(in_params) )
	{
		first_func_param = list_first_entry( in_params , struct ZlangFunctionParameter , this_param ) ;
		list_for_each_entry( func_param , in_params , struct ZlangFunctionParameter , this_param )
		{
			if( func_param != first_func_param )
			{
				len = snprintf( p , remain_len , "," ) ;
				if( len >= 0 )
				{
					p += len ;
					remain_len -= len ;
				}
			}
			
			len = snprintf( p , remain_len , "%s" , func_param->parent_obj_name ) ;
			if( len >= 0 )
			{
				p += len ;
				remain_len -= len ;
			}
		}
	}
	
	len = snprintf( p , remain_len , ")" ) ;
	if( len >= 0 )
	{
		p += len ;
		remain_len -= len ;
	}
	
	p = ZLSTRDUP(full_function_name_buf) ;
	if( p == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_STRDUP , "alloc memory for full func name failed" )
		return NULL;
	}
	
	return p;
}

struct ZlangFunction *CreateFunction( struct ZlangRuntime *rt , char *func_name , char *full_func_name , ZlangInvokeFunction *invoke_func )
{
	struct ZlangFunction	*func = NULL ;
	int			nret = 0 ;
	
	func = (struct ZlangFunction *)ZLMALLOC( sizeof(struct ZlangFunction) ) ;
	if( func == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for func failed" )
		return NULL;
	}
	memset( func , 0x00 , sizeof(struct ZlangFunction) );
	
	if( func_name )
	{
		nret = SetFunctionName( rt , func , func_name ) ;
		if( nret )
		{
			return NULL;
		}
	}
	
	if( full_func_name )
	{
		nret = SetFullFunctionName( rt , func , full_func_name ) ;
		if( nret )
		{
			return NULL;
		}
	}
	
	INIT_LIST_HEAD( & (func->in_params) );
	
	func->invoke_func = invoke_func ;
	
	return func;
}

void FreeFunction( struct ZlangFunction *func )
{
	struct ZlangFunctionParameter	*func_param = NULL ;
	struct ZlangFunctionParameter	*next_func_param = NULL ;
	
	if( func->func_name )
		ZLFREE( func->func_name );
	if( func->full_func_name )
		ZLFREE( func->full_func_name );
	
	list_for_each_entry_safe( func_param , next_func_param , & (func->in_params) , struct ZlangFunctionParameter , this_param )
	{
		FreeFunctionParamter( func_param );
	}
	
	FreeFunctionParamter( func->out_param );
	
	if( IsSynchronizeFunction(func) )
	{
		UnsetSynchronizeFunction( func );
	}
	
	ZLFREE( func );
	
	return;
}

struct ZlangFunctionParameter	_zlang_func_param_void = { "void" , NULL } ;

struct ZlangFunctionParameter *SetFunctionOutputParameterInFunction( struct ZlangRuntime *rt , struct ZlangFunction *func , char *parent_obj_name )
{
	/*
	if( STRCMP( parent_obj_name , == , "void" ) )
		return & _zlang_func_param_void;
	*/
	
	func->out_param = AllocFunctionParamter( rt , parent_obj_name , NULL ) ;
	if( func->out_param == NULL )
		return NULL;
	
	return func->out_param;
}

struct ZlangFunctionParameter *AddFunctionInputParameterInFunction( struct ZlangRuntime *rt , struct ZlangFunction *func , char *parent_obj_name , char *obj_name )
{
	struct ZlangFunctionParameter	*func_param = NULL ;
	
	func_param = AllocFunctionParamter( rt , parent_obj_name , obj_name ) ;
	if( func_param == NULL )
		return NULL;
	
	list_add_tail( & (func_param->this_param) , & (func->in_params) );
	
	return func_param;
}

struct ZlangFunctionParameter *TravelFunctionInputParameter( struct ZlangRuntime *rt , struct ZlangFunction *func , struct ZlangFunctionParameter *func_param )
{
	if( func_param == NULL )
		func_param = list_first_entry( & (func->in_params) , struct ZlangFunctionParameter , this_param ) ;
	else
		func_param = list_next_entry( func_param , struct ZlangFunctionParameter , this_param ) ;
	
	if( & (func_param->this_param) == & (func->in_params) )
		return NULL;
	else
		return func_param;
}

char *GetFunctionParameterParentObjectName( struct ZlangFunctionParameter *func_param )
{
	return func_param->parent_obj_name;
}

char *GetFunctionParameterObjectName( struct ZlangFunctionParameter *func_param )
{
	return func_param->obj_name;
}

struct ZlangFunctionParameter *GetFunctionOutParameter( struct ZlangFunction *func )
{
	return func->out_param;
}

void RemoveFunctionInObject( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangFunction *func )
{
	if( obj->funcs_enti )
	{
		UnlinkFunctionFromFunctionsEntityFunctionsTree( obj->funcs_enti , func );
		
		FreeFunction( func );
	}
	
	return;
}

struct ZlangFunction *AddFunctionAndParametersInObject( struct ZlangRuntime *rt , struct ZlangObject *obj , char *func_name , char *full_func_name , ZlangInvokeFunction *invoke_func , char *out_param_parent_obj_name , ... )
{
	struct ZlangFunction		*func = NULL ;
	struct ZlangFunctionParameter	*func_param = NULL ;
	va_list				valist ;
	char				*parent_obj_name = NULL ;
	char				*obj_name = NULL ;
	int				nret = 0 ;
	
	func = CreateFunction( rt , func_name , full_func_name , invoke_func ) ;
	if( func == NULL )
	{
		return NULL;
	}
	
	func_param = SetFunctionOutputParameterInFunction( rt , func , out_param_parent_obj_name ) ;
	if( func_param == NULL )
	{
		FreeFunction( func );
		return NULL;
	}
	
	va_start( valist , out_param_parent_obj_name );
	for( ; ; )
	{
		parent_obj_name = va_arg( valist , char* ) ;
		if( parent_obj_name == NULL )
			break;
		obj_name = va_arg( valist , char* ) ;
		
		func_param = AddFunctionInputParameterInFunction( rt , func , parent_obj_name , obj_name ) ;
		if( func_param == NULL )
		{
			FreeFunction( func );
			return NULL;
		}
	}
	va_end( valist );
	
	nret = AddFunctionToObjectFunctionsEntity( rt , obj , func ) ;
	if( nret )
	{
		FreeFunction( func );
		return NULL;
	}
	
	return func;
}

struct ZlangFunction *CreateFunctionFromFunction( struct ZlangRuntime *rt , struct ZlangFunction *copy_func )
{
	struct ZlangFunction		*func = NULL ;
	struct ZlangFunctionParameter	*copy_func_param = NULL ;
	struct ZlangFunctionParameter	*func_param = NULL ;
	
	func = CreateFunction( rt , copy_func->func_name , copy_func->full_func_name , copy_func->invoke_func ) ;
	if( func == NULL )
	{
		return NULL; 
	}
	
	copy_func_param = NULL ;
	while( ( copy_func_param = TravelFunctionInputParameter( rt , copy_func , copy_func_param ) ) )
	{
		func_param = AddFunctionInputParameterInFunction( rt , func , copy_func_param->parent_obj_name , copy_func_param->obj_name ) ;
		if( func_param == NULL )
		{
			FreeFunction( func );
			return NULL;
		}
	}
	
	if( copy_func->out_param )
	{
		func_param = SetFunctionOutputParameterInFunction( rt , func , copy_func->out_param->parent_obj_name ) ;
		if( func_param == NULL )
		{
			FreeFunction( func );
			return NULL;
		}
	}
	
	func->access_qualifier = copy_func->access_qualifier ;
	
	func->func_begin_token_datapage_header = copy_func->func_begin_token_datapage_header ;
	func->func_begin_token_dataunit = copy_func->func_begin_token_dataunit ;
	func->func_end_over_token_datapage_header = copy_func->func_end_over_token_datapage_header ;
	func->func_end_over_token_dataunit = copy_func->func_end_over_token_dataunit ;
	
	return func;
}

struct ZlangFunction *QueryFunctionByFullFunctionNameInObject( struct ZlangRuntime *rt , struct ZlangObject *obj , char *full_func_name )
{
	struct ZlangFunctionsEntity	*funcs_enti = NULL ;
	struct ZlangFunction		f ;
	struct ZlangFunction		*func = NULL ;
	
	funcs_enti = GetObjectFunctionsEntity(obj) ;
	if( funcs_enti )
	{
		memset( & f , 0x00 , sizeof(struct ZlangFunction) );
		f.full_func_name = full_func_name ;
		
_GOTO_RETRY_ANCESTOR_FUNCTIONS_ENTITY :
		func = QueryFunctionInFunctionsEntityFunctionsTreeByFullFunctionName( funcs_enti , & f ) ;
		if( func == NULL )
		{
			if( funcs_enti->ancestor_funcs_enti )
			{
				funcs_enti = funcs_enti->ancestor_funcs_enti ;
				goto _GOTO_RETRY_ANCESTOR_FUNCTIONS_ENTITY;
			}
		}
	}
	
	return func;
}

struct ZlangFunction *AddGlobalFunctionAndParameters( struct ZlangRuntime *rt , char *func_name , char *full_func_name , ZlangInvokeFunction *invoke_func , char *out_param_parent_obj_name , ... )
{
	struct ZlangFunction		*func = NULL ;
	struct ZlangFunctionParameter	*func_param = NULL ;
	va_list				valist ;
	char				*parent_obj_name = NULL ;
	char				*obj_name = NULL ;
	int				nret = 0 ;
	
	func = CreateFunction( rt , func_name , full_func_name , invoke_func ) ;
	if( func == NULL )
	{
		return NULL;
	}
	
	func_param = SetFunctionOutputParameterInFunction( rt , func , out_param_parent_obj_name ) ;
	if( func_param == NULL )
	{
		FreeFunction( func );
		return NULL;
	}
	
	va_start( valist , out_param_parent_obj_name );
	for( ; ; )
	{
		parent_obj_name = va_arg( valist , char* ) ;
		if( parent_obj_name == NULL )
			break;
		obj_name = va_arg( valist , char* ) ;
		
		func_param = AddFunctionInputParameterInFunction( rt , func , parent_obj_name , obj_name ) ;
		if( func_param == NULL )
		{
			FreeFunction( func );
			return NULL;
		}
	}
	va_end( valist );
	
	nret = LinkFunctionToRuntimeFunctionsTreeByFullFunctionName( rt , func ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_LINK_FUNC_TO_ENTITY , "link function[%s][%s] in runtime failed" , func->func_name,func->full_func_name )
		FreeFunction( func );
		return NULL;
	}
	
	return func;
}

struct ZlangFunction *QueryGlobalFunctionByFullFunctionName( struct ZlangRuntime *rt , char *full_func_name )
{
	struct ZlangFunction	f ;
	
	memset( & f , 0x00 , sizeof(struct ZlangFunction) );
	f.full_func_name = full_func_name ;
	return QueryFunctionInRuntimeFunctionsTreeByFullFunctionName( rt , & f );
}

struct ZlangFunction *TravelGlobalFunctionByFullFunctionName( struct ZlangRuntime *rt , struct ZlangFunction *func )
{
	return TravelFunctionInRuntimeFunctionsTreeByFullFunctionName( rt , func );
}

int SetSynchronizeFunction( struct ZlangFunction *func )
{
	pthread_mutexattr_t	attr ;
	int			nret = 0 ;
	
	if( func == NULL )
		return -1;
	
	if( func->synchronize_lock == 0 )
	{
		func->synchronize_lock = (struct ZlangMutexLock *)malloc( sizeof(struct ZlangMutexLock) ) ;
		if( func->synchronize_lock == NULL )
			return ZLANG_ERROR_ALLOC;
		memset( func->synchronize_lock , 0x00 , sizeof(struct ZlangMutexLock) );
		
		pthread_mutexattr_init( & attr );
		pthread_mutexattr_settype( & attr , PTHREAD_MUTEX_RECURSIVE_NP );
		nret = pthread_mutex_init( & (func->synchronize_lock->lock) , & attr ) ;
		pthread_mutexattr_destroy( & attr );
		
		__sync_add_and_fetch( & (func->synchronize_lock->refer_count) , 1 );
	}
	
	return nret;
}

int UnsetSynchronizeFunction( struct ZlangFunction *func )
{
	if( func == NULL )
		return -1;
	
	if( func->synchronize_lock )
	{
		if( __sync_sub_and_fetch( & (func->synchronize_lock->refer_count) , 1 ) == 0 )
		{
			pthread_mutex_destroy( & (func->synchronize_lock->lock) );
			free( func->synchronize_lock ); func->synchronize_lock = NULL ;
		}
	}
	
	return 0;
}

unsigned char IsSynchronizeFunction( struct ZlangFunction *func )
{
	if( func == NULL )
		return 0;
	
	return func->synchronize_lock?1:0;
}

int LockSynchronizeFunction( struct ZlangFunction *func )
{
	int		nret = 0 ;
	
	if( func == NULL )
		return -1;
	
	if( func->synchronize_lock )
	{
		nret = pthread_mutex_lock( & (func->synchronize_lock->lock) ) ;
	}
	
	return nret;
}

int UnlockSynchronizeFunction( struct ZlangFunction *func )
{
	int		nret = 0 ;
	
	if( func == NULL )
		return -1;
	
	if( func->synchronize_lock )
	{
		nret = pthread_mutex_unlock( & (func->synchronize_lock->lock) ) ;
	}
	
	return nret;
}

void CopySynchronizeFunction( struct ZlangFunction *func , struct ZlangFunction *copy_func )
{
	if( IsSynchronizeFunction(copy_func) )
	{
		func->synchronize_lock = copy_func->synchronize_lock ;
		__sync_add_and_fetch( & (func->synchronize_lock->refer_count) , 1 );
	}
	
	return;
}

void DebugPrintFunction( struct ZlangRuntime *rt , struct ZlangFunction *func )
{
	struct ZlangFunctionParameter	*in_param = NULL ;
	
	if( func->func_begin_token_datapage_header )
	{
		struct ZlangTokenDataUnitHeader	*token_info = (struct ZlangTokenDataUnitHeader *)GetAppendonlyDataUnitUserHeader(func->func_begin_token_dataunit) ;
		char				*token = (char*)token_info + sizeof(struct ZlangTokenDataUnitHeader) ;
		struct ZlangTokenDataUnitHeader	*token_info2 = (struct ZlangTokenDataUnitHeader *)GetAppendonlyDataUnitUserHeader(func->func_end_over_token_dataunit) ;
		char				*token2 = (char*)token_info2 + sizeof(struct ZlangTokenDataUnitHeader) ;
		
		TOKENTYPE_TO_STRING( token_info->token_type , _zlang_token_type_str )
		TOKENTYPE_TO_STRING( token_info2->token_type , _zlang_token_type_str2 )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "  func[%p] func_name[%s] full_func_name[%s] access_qualifier[%d] is_interceptor[%d] invoke_func[%p] begin[%s][%"PRIi32"][%"PRIi32"]-[%s][%"PRIi32"]-[%p][%p][%d]-[%.*s] end_over[%s][%"PRIi32"][%"PRIi32"]-[%s][%"PRIi32"]-[%p][%p][%d]-[%.*s] sync[%p]"
		, func , func->func_name , func->full_func_name , func->access_qualifier , func->is_interceptor , func->invoke_func
		, token_info->source_filename,token_info->source_row,token_info->source_col , _zlang_token_type_str,token_info->token_len , token_info->p1,token_info->p2,token_info->n3 , token_info->token_len,token
		, token_info2->source_filename,token_info2->source_row,token_info->source_col , _zlang_token_type_str2,token_info2->token_len , token_info2->p1,token_info2->p2,token_info2->n3 , token_info2->token_len,token2
		, func->synchronize_lock );
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "  func[%p] func_name[%s] full_func_name[%s] access_qualifier[%d] is_interceptor[%d] invoke_func[%p]" , func , func->func_name , func->full_func_name , func->access_qualifier , func->is_interceptor , func->invoke_func )
	}
	
	list_for_each_entry( in_param , & (func->in_params) , struct ZlangFunctionParameter , this_param )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "   IN  param[%p] parent_obj_name[%s] obj_name[%s]" , in_param , in_param->parent_obj_name , in_param->obj_name );
	}
	
	if( func->out_param )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "   OUT param[%p] parent_obj_name[%s] obj_name[%s]" , func->out_param , func->out_param->parent_obj_name , func->out_param->obj_name );
	}
	
	return;
}

#if 0
void DebugPrintFunctionsEntity( struct ZlangRuntime *rt , struct ZlangFunctionsEntity *funcs_enti )
{
	struct ZlangFunction	*func = NULL ;
	
	if( funcs_enti == NULL )
		return;
	
	func = NULL ;
	for( ; funcs_enti ; )
	{
		func = TravelFunctionFromFunctionsEntityFunctionsTreeByFullFunctionName( funcs_enti , func ) ;
		if( func == NULL )
			break;
		
		DebugPrintFunction( rt , func );
	}
	
	if( funcs_enti->ancestor_funcs_enti )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "  ancestor[%s]" , funcs_enti->ancestor_funcs_enti->type_name );
		
		OffsetRuntimeRecursizeDepth( rt , 1 );
		
		DebugPrintFunctionsEntity( rt , funcs_enti->ancestor_funcs_enti );
		
		OffsetRuntimeRecursizeDepth( rt , -1 );
	}
	
	return;
}
#endif

void DebugBeforeCallFunction( struct ZlangRuntime *rt , struct ZlangFunction *func )
{
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "before call func , func_name[%s] full_func_name[%s]" , func->func_name,func->full_func_name );
	
	DebugStack( rt );
	
	return;
}

void DebugAfterCallFunction( struct ZlangRuntime *rt , struct ZlangFunction *func )
{
	PRINT_TABS_AND_FORMAT( rt , "after call func , func_name[%s] full_func_name[%s]" , func->func_name,func->full_func_name );
	
	DebugStack( rt );
	
	return;
}

